package com.rtuwrapper.connection;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.util.Log;
import android.widget.Toast;

import com.felhr.usbserial.Rs232SerialDevice;
import com.felhr.usbserial.UsbSerialDevice;
import com.appfront.debug.App;

// TODO: 23.05.17 add reconnection logic
public class ModbusRtuConnection {

    public interface OnConnectedToPlcListener {
        void onConnected(boolean connected, boolean isUSBDevice);
    }

    private static final String ACTION_USB_PERMISSION = "com.appfront.USB_PERMISSION";
    public static String ManufacturerString = "mManufacturer=FTDI";
    public static String ModelString1 = "mModel=FTDIUARTDemo";
    public static String ModelString2 = "mModel=Android Accessory FT312D";
    public static String VersionString = "mVersion=1.0";
    public boolean mPermissionRequestPending = false;
    public PendingIntent pendingIntent;
    private Context context;
    private int vendorId;

    public UsbManager usbManager;
    private UsbDevice usbDevice;
    private UsbSerialDevice usbSerialDevice;
    private Rs232SerialDevice rs232SerialDevice;
    private UsbDeviceConnection usbDeviceConnection;
    private SerialParameters serialParameters;

    private BroadcastReceiver broadcastReceiver;

    private boolean connectOnDeviceAttached;

    private OnConnectedToPlcListener listener;

    public ModbusRtuConnection(Context context, int vendorId, boolean connectOnDeviceAttached) {
        this.vendorId = vendorId;
        this.connectOnDeviceAttached = connectOnDeviceAttached;
        this.context = context;
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
        createBroadcastReceiver();
        if (broadcastReceiver != null) {
            context.registerReceiver(broadcastReceiver, filter);
        }
    }

    private void createBroadcastReceiver() {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
                    UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
                    {
                        Toast.makeText(context, "Allow USB Permission", Toast.LENGTH_SHORT).show();
                        openUsbSerialDevice(serialParameters, accessory);
                    }
                    else
                    {
                        Toast.makeText(context, "Deny USB Permission", Toast.LENGTH_SHORT).show();
                        Log.d("LED", "permission denied for accessory "+ accessory);
                    }
                    mPermissionRequestPending = false;
                } else if (intent.getAction().equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)) {
                    if (App.IS_DEBUG) System.out.println("USB - DEVICE DETACHED");
                    if(null != usbSerialDevice)
                        usbSerialDevice.close();
                    listener.onConnected(false, true);
                }
            }
        };
    }

    private void openUsbSerialDevice(SerialParameters serialParameters, UsbAccessory accessory) {
        usbSerialDevice = new UsbSerialDevice(accessory, usbManager);
        if (usbSerialDevice != null) {
            if (usbSerialDevice.open()) { //Set Serial Connection Parameters.
                if (serialParameters == null) {
                    serialParameters = SerialParameters.getDefault();
                }
                usbSerialDevice.setBaudRate(serialParameters.baudRate);
                usbSerialDevice.setDataBits(serialParameters.databits);
                usbSerialDevice.setStopBits(serialParameters.stopbits);
                usbSerialDevice.setParity(serialParameters.parity);
                usbSerialDevice.setFlowControl(serialParameters.flowControl);
                if (listener != null) {
                    listener.onConnected(true, true);
                }
                Toast.makeText(context, "USB - SERIAL DEVICE OPEN SUCCESS", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "USB - SERIAL DEVICE NOT OPEN", Toast.LENGTH_SHORT).show();
                if (App.IS_DEBUG) System.out.println("USB - SERIAL DEVICE NOT OPEN");
            }
        } else {
            Toast.makeText(context, "USB - SERIAL DEVICE IS NULL", Toast.LENGTH_SHORT).show();
            if (App.IS_DEBUG) System.out.println("USB - SERIAL DEVICE IS NULL");
        }
    }

    public UsbSerialDevice getUsbSerialDevice() {
        if (usbSerialDevice != null) {
            return usbSerialDevice;
        }
        return null;
    }

    public Rs232SerialDevice getRs232SerialDevice() {
        if (rs232SerialDevice != null) {
            return rs232SerialDevice;
        }
        return null;
    }

    public void connect(OnConnectedToPlcListener listener) {
        this.listener = listener;
        //requestPermission();
    }

    public void disconnect() {
        if(null != usbSerialDevice)
            usbSerialDevice.close();
    }

    public int requestPermission() {

        UsbAccessory[] accessories = usbManager.getAccessoryList();
        if(accessories == null){
            //Toast.makeText(context, "esumeAccessory RETURN 2 (accessories == null)", Toast.LENGTH_SHORT).show();
            return 2;
        }

        UsbAccessory accessory = (accessories == null ? null : accessories[0]);
        if (accessory != null) {
            if( -1 == accessory.toString().indexOf(ManufacturerString))
            {
                Toast.makeText(context, "Manufacturer is not matched!", Toast.LENGTH_SHORT).show();
                return 1;
            }

            if( -1 == accessory.toString().indexOf(ModelString1) && -1 == accessory.toString().indexOf(ModelString2))
            {
                Toast.makeText(context, "Model is not matched!", Toast.LENGTH_SHORT).show();
                return 1;
            }

            if( -1 == accessory.toString().indexOf(VersionString))
            {
                Toast.makeText(context, "Version is not matched!", Toast.LENGTH_SHORT).show();
                return 1;
            }
            //Toast.makeText(context, "Manufacturer, Model & Version are matched!", Toast.LENGTH_SHORT).show();

            if (usbManager.hasPermission(accessory)) {
                openUsbSerialDevice(serialParameters, accessory);
                return 0;
            }
            else
            {
                synchronized (broadcastReceiver) {
                    if (!mPermissionRequestPending) {
                        Toast.makeText(context, "start Request USB Permission", Toast.LENGTH_SHORT).show();
                        usbManager.requestPermission(accessory, pendingIntent);
                        mPermissionRequestPending = true;
                    }
                }
            }
        }else{
            return 1;
        }

        return 1;
    }

    public void requestRS232Serial(String filePath, int baundRate){
        rs232SerialDevice = new Rs232SerialDevice(filePath, baundRate);
        if(true == rs232SerialDevice.open()) {
            listener.onConnected(true, false);
        }
    }
}


//    private void findDevice() {
//        HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
//        if (!usbDevices.isEmpty()) {
//            for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
//                if (entry.getValue().getVendorId() == vendorId) { //vendor ID check
//                    if (App.IS_DEBUG) System.out.println("USB - VENDOR ID MATCH");
//                    usbDevice = entry.getValue();
//                    break;
//                }
//            }
//        } else if (App.IS_DEBUG) {
//            System.out.println("USB DEVICES LIST IS EMPTY");
//        }
//    }